package xslice

import (
	"gitee.com/gousing/helper/internal"
)

// First 取得Slice切片的(左端)第一个元素
//   - 切片为空，返回空值(零值)
func First[T any](v []T) (val T) {
	if len(v) == 0 {
		return
	}
	return v[0]
}

// Last 取得Slice切片的(左端)第一个非零值元素
//   - 切片为空，返回空值(零值)
//   - 注意: 切片元素为Bool时, 此元素约定为非零值
func FirstNotZero[T any](v []T) (val T) {
	if len(v) == 0 {
		return
	}
	for _, item := range v {
		switch any(item).(type) {
		case bool:
			return item
		default:
			if !internal.IsZero(item) {
				return item
			}
		}
	}
	return
}

// Last 取得Slice切片的(右端)最后一个元素
//   - 切片为空，返回空值(零值)
func Last[T any](v []T) (val T) {
	if len(v) == 0 {
		return
	}
	return v[len(v)-1]
}

// Last 取得Slice切片的(右端)最后一个非零值元素
//   - 切片为空，返回空值(零值)
//   - 注意: 切片元素为Bool时, 全部元素约定为非零值
func LastNotZero[T any](v []T) (val T) {
	if len(v) == 0 {
		return
	}
	for i := len(v) - 1; i >= 0; i-- {
		switch any(v[i]).(type) {
		case bool:
			return v[i]
		default:
			if !internal.IsZero(v[i]) {
				return v[i]
			}
		}
	}
	return
}

// Has 切片内是否含有某个元素
func Has[T comparable](sliceVal []T, val T) bool {
	if len(sliceVal) == 0 {
		return false
	}
	for _, item := range sliceVal {
		if item == val {
			return true
		}
	}
	return false
}

// Unique 切片去重（保留顺序）
//   - 待处理切片为nil是返回nil,
//   - 待处理切片长度为0时, 返回空的 []T 切片
func Unique[T comparable](sliceVal []T) (uniqueSlice []T) {
	if sliceVal == nil {
		return nil
	}
	length := len(sliceVal)
	if length == 0 {
		return []T{}
	}
	temp := make(map[T]struct{}, length)
	uniqueSlice = make([]T, 0, length)
	for _, item := range sliceVal {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			uniqueSlice = append(uniqueSlice, item)
		}
	}
	return uniqueSlice
}

// PushUnique 去重方式添加元素
func PushUnique[T comparable](slices []T, val T) (uniqueSlice []T) {
	if len(slices) == 0 {
		return []T{val}
	}
	temp := make(map[T]struct{})
	uniqueSlice = make([]T, 0, len(slices)+1)
	for _, item := range slices {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			uniqueSlice = append(uniqueSlice, item)
		}
	}
	if _, ok := temp[val]; !ok {
		uniqueSlice = append(uniqueSlice, val)
	}
	return uniqueSlice
}

// UnsortedEqual 判断两个无序的切片元素是否相同(长度相等,忽略顺序含有相同元素)
func UnsortedEqual[T comparable](input []T, expected []T) bool {
	l := len(input)
	if l != len(expected) {
		return false
	}
	// 零长度切片相等
	if l == 0 {
		return true
	}
	// 只有一个元素, 快速比较
	if l == 1 {
		return input[0] == expected[0]
	}
	// 多个元素需要遍历比较
	// 创建一个计数映射
	countMap := make(map[T]int, l)

	// 增加 input 中每个元素的计数
	for _, item := range input {
		countMap[item]++
	}

	// 减少 expected 中每个元素的计数，并检查是否存在非法情况
	for _, item := range expected {
		if _, exists := countMap[item]; !exists {
			return false
		}
		countMap[item]--
		if countMap[item] < 0 {
			return false
		}
	}

	return true
}
